package easyui

import (
	"database/sql"
	"encoding/json"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/gorilla/websocket"
	"github.com/liuhangkaixcode/lhktools"
	"github.com/menduo/gobaidumap"
	"math/rand"
	"net/http"
	"sync"
	"time"
)

var (
	mm          string
	kk          []map[string]interface{}
	// Time allowed to write a message to the peer.
	writeWait = 10 * time.Second // 10

	// Time allowed to read the next pong message from the peer.
	pongWait = 30 * time.Second //60

	// Send pings to peer with this period. Must be less than pongWait.
	pingPeriod = (pongWait * 9) / 10

	// Maximum message size allowed from peer.
	maxMessageSize = 512
	//dns1        = "root:123456@tcp(127.0.0.1:3309)/db?timeout=10s&readTimeout=12s"
	dns1        = "lhk:h5ZEbxcJxSeSykmH@tcp(114.132.223.140:3306)/lhk?timeout=10s&readTimeout=12s"
	mysqlmanger = lhktools.NewMysql(dns1)
	WebSocketMap =make(map[string]*websocket.Conn,1000)
	upgrader = websocket.Upgrader{
		CheckOrigin:func(r *http.Request) bool{
			return true
		},
	}
	lock sync.RWMutex
)


const NOSQLROW = "sql: no rows in result set"



type WebSocketMsg struct {
	From string `json:"from"`
	To string `json:"to"`
	Service string `json:"service"`
	MsgType int  `json:"type"`
	Content string `json:"content"`
	MsgError string `json:"errmsg"`
}

const (
	SOCKET_CLOSE =1
	SOCKET_MSG =2
	SOCKET_MSG_FORMAT=3
	SOCKET_MSG_ERROR=4
)
func getWebMsg(s WebSocketMsg) []byte {
	s.Service="easyui"
	marshal, err := json.Marshal(s)
	if err!=nil{
		fmt.Println("err",err)
		return nil
	}
	return marshal
}

func getWebStruct(s string)WebSocketMsg  {
	var w WebSocketMsg

	err := json.Unmarshal([]byte(s),&w)
	if err!=nil{
		fmt.Println("err",err)
		return w
	}
	w.Service="easyui"
	return w
}
func readerMessage(ch chan string, conn *websocket.Conn, userid string) {
	defer func() {
		fmt.Println("读的时候-关闭连接了")
		conn.Close()
	}()

	conn.SetReadLimit(int64(maxMessageSize))
	conn.SetReadDeadline(time.Now().Add(pongWait))
	conn.SetPongHandler(func(t string) (ee error) {
		//fmt.Println("pong callBack-->", t, ee, time.Now().String())
		conn.SetReadDeadline(time.Now().Add(pongWait))
		return
	})
	for {
		messageType, data, err := conn.ReadMessage()
		datastr := string(data)
		fmt.Println("读取所有的信息-->", messageType, err, datastr, websocket.CloseMessage)

		if err != nil || messageType == websocket.CloseMessage {

			// 其他错误，如果是 1001 和 1000 就不打印日志
			if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseNormalClosure) {
				fmt.Printf("ReadMessage other remote:%v error: %v \n", conn.RemoteAddr(), err)
			}
			lock.Lock()
			if conn != nil {
				delete(WebSocketMap, userid)
			}
			lock.Unlock()
			return
		}

		//ch <- datastr

	}
}

func writeMes(ch chan string, conn *websocket.Conn, userid string) {
	pingTicker := time.NewTicker(pingPeriod)
	defer func() {
		pingTicker.Stop()
		fmt.Println("===>ping干掉了")
		conn.Close()
	}()
	for {
		select {
		//case datastr := <-ch:
		//	{
		//		//处理业务
		//		temp:=getWebStruct(datastr)
		//		if len(temp.To) >0 && temp.MsgType == SOCKET_MSG {
		//			temp.From=userid
		//			lock.RLock()
		//			if v, ok := WebSocketMap[temp.To]; ok {
		//				fmt.Println("==>fasong", temp.Content)
		//				v.SetWriteDeadline(time.Now().Add(writeWait))
		//				v.WriteMessage(websocket.TextMessage, []byte(getWebMsg(temp)))
		//			}else {
		//				conn.SetWriteDeadline(time.Now().Add(writeWait))
		//				temp.MsgError="对应的id发送者找不到"
		//				conn.WriteMessage(websocket.TextMessage, getWebMsg(temp))
		//			}
		//			lock.RUnlock()
		//
		//		} else if  len(temp.To) >0 && temp.MsgType == SOCKET_CLOSE{
		//					lock.RLock()
		//					if v, ok := WebSocketMap[temp.From]; ok {
		//						v.Close()
		//						fmt.Println("==>关闭了-", temp.Content)
		//					}
		//					lock.RUnlock()
		//
		//		}else{
		//
		//			var temp WebSocketMsg
		//			temp.From=userid
		//			temp.MsgType=SOCKET_MSG_FORMAT
		//			temp.MsgError="消息格式不正确"
		//			conn.WriteMessage(websocket.TextMessage,getWebMsg(temp))
		//		}
		//
		//		//END
		//	}


		case <-pingTicker.C:
			{

				control := conn.WriteMessage(websocket.PingMessage, nil)
				if control != nil {
					fmt.Println("===控制小===》》",control)
					return
				}
			}
		}
	}
}

func Cors() gin.HandlerFunc {
	return func(c *gin.Context) {
		method := c.Request.Method
		c.Header("Access-Control-Allow-Origin", "*")
		c.Header("Access-Control-Allow-Headers", "Content-Type,AccessToken,X-CSRF-Token, Authorization, Token")
		c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS")
		c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type")
		c.Header("Access-Control-Allow-Credentials", "true")

		// 放行所有OPTIONS方法
		if method == "OPTIONS" {
			c.AbortWithStatus(http.StatusNoContent)
		}
		// 处理请求
		c.Next()
	}
}



type Menu struct {
	Id      int            `db:"id" json:"db"`
	Text    string         `db:"text" json:"text"`
	Path    JsonNullString `db:"path" json:"path"`
	IsDir   int            `db:"isdir" json:"isdir"`
	Pid     int            `db:"pid" json:"pid"`
	SortNum int            `db:"sortnum" json:"sortnum"`
	Checked bool           `db:"checked" json:"checked"`
}
type TreeList struct {
	Id       int        `json:"id" db:"id"`
	Pid      int        `json:"pid" db:"pid"`
	Text     string     `json:"text" db:"text"`
	Path     string     `json:"path" db:"path"`
	IsDir    int        `json:"isdir" db:"isdir"`
	Checked  bool       `db:"checked" json:"checked"`
	Children []TreeList `json:"children"`
	SortNum  int        `json:"sortnum" db:"sortnum"`
	State  string `json:"state" db:"state"`
}
type JsonNullString struct {
	sql.NullString

}

func getTime() int {
	rand.Seed(time.Now().UnixNano())
	//生成10个0-99之间的随机数
	return rand.Intn(100000)
}
//kaishi
func (v JsonNullString) MarshalJSON() ([]byte, error) {
	if v.Valid {
		return json.Marshal(v.String)
	} else {
		return json.Marshal(nil)
	}
}

func (v *JsonNullString) UnmarshalJSON(data []byte) error {
	// Unmarshalling into a pointer will let us detect null
	var x *string
	if err := json.Unmarshal(data, &x); err != nil {
		return err
	}
	if x != nil {
		v.Valid = true
		v.String = *x
	} else {
		v.Valid = false
	}
	return nil
}

func GetMenu(menuList []Menu, pid int) []TreeList {
	treeList := []TreeList{}
	for _, v := range menuList {
		if v.Pid == pid {
			child := GetMenu(menuList, v.Id)
			node := TreeList{
				Id:      v.Id,
				Text:    v.Text,
				Pid:     v.Pid,
				Path:    v.Path.String,
				SortNum: v.SortNum,
				IsDir:   v.IsDir,
				Checked: v.Checked,
			}
			node.Children = child
			treeList = append(treeList, node)
		}
	}
	return treeList
}
func SelectSort(data []Menu) []Menu {
	var result []Menu
	var pids []int
	for _, v := range data {
		pids = append(pids, v.Pid)
	}
	pids = RemoveRepByLoop(pids)
	for _, values := range pids {
		var tempids []Menu
		for _, m := range data {
			if values == m.Pid {
				tempids = append(tempids, m)
			}
		}

		if len(tempids) > 1 {
			//进行排序
			for i := 0; i < len(tempids); i++ {
				for j := i + 1; j < len(tempids); j++ {
					if tempids[i].SortNum < tempids[j].SortNum {
						tempids[j], tempids[i] = tempids[i], tempids[j]
					}
				}
			}
			//排序结束
		}

		result = append(result, tempids...)
	}
	return result
}
func RemoveRepByLoop(slc []int) []int {
	result := []int{} // 存放结果
	for i := range slc {
		flag := true
		for j := range result {
			if slc[i] == result[j] {
				flag = false // 存在重复元素，标识为false
				break
			}
		}
		if flag { // 标识为false，不添加进结果
			result = append(result, slc[i])
		}
	}
	return result
}

///复杂了
func getTokenMeun(dir,tokenmenu,all []Menu) ([]Menu)  {
	var fina []Menu
	var orderID []int //所有的子菜单
	var orderpid []int //直系父目录
	for _,k:=range tokenmenu{
		orderID =append(orderID,k.Id)
		orderpid=append(orderpid,k.Pid)
	}
	orderID=append(orderID,orderpid...)

	orderID=findDir(orderID,orderpid,dir) //遍历去递归往上找父目录

	orderID=RemoveRepByLoop(orderID)


	for _,temp:=range all{
		for _,i:=range orderID{
			if i == temp.Id{
				fina=append(fina,temp)
			}
		}
	}

	return fina
}

func findDir(orderID,orderpid []int,dir []Menu) []int{

	for _,value:=range orderpid{
		if value ==0 {
			continue
		}
		for _,sub:=range dir{
			if value ==sub.Id{
				orderID=append(orderID,sub.Id)
				if sub.Pid==0{
					break
				}
				return  xxx(sub,dir,orderID)
			}
		}
	}
	return orderID
}

func xxx(need Menu ,dir []Menu,orderID []int) []int {
	if need.Pid ==0{
		return orderID
	}
	for _,sub:=range dir{
		if need.Pid == sub.Id{

			orderID=append(orderID,sub.Id)

			return xxx(sub,dir,orderID)
		}
	}
	return orderID
}

func getlocation(ipstr string)map[string]string  {
	//var lat string = "19.9139658858"
	//var lng string = "110.2107238770"
	//client := gobaidumap.NewBaiduMapClient("fns3F8iVLlCCEoYbc0OZp8klpWcyfRiB")
	//
	////从坐标到地址
	//locationToaddress, err := client.GetAddressViaGEO(lat, lng)
	//if err != nil {
	//	fmt.Println(err)
	//} else {
	//	fmt.Println("坐标地址：", locationToaddress)
	//	fmt.Println("坐标地址-地址", locationToaddress.Result.AddressComponent)
	//}
	////有地址到坐标
	//address := "广州市天河区石牌小学"
	//addressToLocation, err := client.GetGeoViaAddress(address)
	//if err != nil {
	//	fmt.Println(err)
	//} else {
	//	fmt.Println("从地址到坐标-all", addressToLocation)
	//	fmt.Println("从地址到坐标 - Lat", addressToLocation.Result.Location.Lat)
	//	fmt.Println("从地址到坐标 - Lng", addressToLocation.Result.Location.Lng)
	//	fmt.Println("\n")
	//}
	////由ip到地址
	////ipAddress := "222.76.214.60"
	//ipAddress := "218.77.129.195"
	//IPToAddress, err := client.GetAddressViaIP(ipAddress)
	//if err != nil {
	//	fmt.Println(err)
	//} else {
	//	fmt.Println("从ip到地址：", IPToAddress)
	//	fmt.Println("从ip到地址-地址", IPToAddress.Content.Address)
	//	fmt.Println("\n")
	//}
if len(ipstr)==0{
	return nil
}
	client := gobaidumap.NewBaiduMapClient("fns3F8iVLlCCEoYbc0OZp8klpWcyfRiB")
	result:=make(map[string]string)
	ip, err := client.GetAddressViaIP(ipstr)
	if err!=nil{
		return nil
	}
	address, err := client.GetGeoViaAddress(ip.Content.Address)
	if err!=nil{
		return nil
	}
	result["location"]=ip.Content.Address
	result["lat"]=fmt.Sprintf("%f,%f",address.Result.Location.Lat,address.Result.Location.Lng)
	return result
}

